/**
Author: Brian Fehrman
Class: Computer Vision Fall 2012
Professor: Dr. Hoover
Assign: HW3

This program is a twist on Homework 3. It uses OpenCV to capture video feed
from an attached webcam. Each frame is converted to 32bit float, then 
converted to gray scale, then the program performs an SVD on the gray
scale frame. 7 windows are then output. 6 windows show reconstructions of the
gray scale image using varying rank orders. The other window shows the original
gray scale image. The program is setup so that you can easily change the ranks
used, the step size for the ranks, and the overall number of ranks.


**/

/***** Includes *****/
#include <ctime>
#include <math.h>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
//#include "opencv2/calib3d/calib3d.hpp"
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <sstream>
#include <fstream>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "tbb/blocked_range.h"
#include "tbb/parallel_for.h"
#include <omp.h>


/**** Defines ****/
#define WINDOW_SIZE_CHOICE CV_WINDOW_NORMAL
#define NUM_EXPS 6

/**** Using Statements ****/
using namespace cv;
using namespace std;
using namespace tbb;

/**** Structs ******/

/****Consts********/
const string exposure_base =  "uvcdynctrl -d /dev/video0 -s \"Exposure (Absolute)\" ";
const int NUM_THREADS = 2;

/****** Prototypes *****/
void AUTO();
void HDR();
void combine_imgs( );
void set_exposure( int curr_exp );
void find_w_vals( float pixs[3], float curr_w_vals[3] );
void combine_exps( vector<Mat>& exp_images, Mat& dst );
void video_test( int n );
void get_frames( int id);
void single_video( int id);



/******** Main ***********/

int main( int argc, char *argv[])
{	
	
	 system("uvcdynctrl -d /dev/video1 -s \"Exposure, Auto Priority\" 0");
	// system("uvcdynctrl -d /dev/video1 -s \"Exposure (Absolute)\" 2000");
   //system("uvcdynctrl -d /dev/video1 -s \"Exposure, Auto\" 3");
   	 system("uvcdynctrl -d /dev/video2 -s \"Exposure, Auto Priority\" 0");
   	// system("uvcdynctrl -d /dev/video2 -s \"Exposure (Absolute)\" 2000");
  // system("uvcdynctrl -d /dev/video2 -s \"Exposure, Auto\" 3");
   	 system("uvcdynctrl -d /dev/video3 -s \"Exposure, Auto Priority\" 0");
   	// system("uvcdynctrl -d /dev/video3 -s \"Exposure (Absolute)\" 2000");
  // system("uvcdynctrl -d /dev/video3 -s \"Exposure, Auto\" 3");
   	 system("uvcdynctrl -d /dev/video4 -s \"Exposure, Auto Priority\" 0");
   //	 system("uvcdynctrl -d /dev/video4 -s \"Exposure (Absolute)\" 2000");
  // system("uvcdynctrl -d /dev/video4 -s \"Exposure, Auto\" 3");
	
	/*
	VideoCapture cap( 0 );
	
	for(;;)
	{
		Mat frame_in;
		
		cap >> frame_in;
		
		imshow( "frame", frame_in );
		
		if( waitKey( 30 ) >= 0) break;
		
	}
	* */
	
	get_frames( 0 );
	//video_test( NUM_THREADS );
   //HDR();
   //AUTO();
	return 0;
}

void get_frames( int id )
{
	//id++;
	int nrows = 120;
	int ncols = 160;
	VideoCapture cam[ NUM_THREADS ];
	//VideoWriter output_vid( "camera_array_4.avi", CV_FOURCC('D', 'I', 'V', 'X'), 15, Size( ncols * 2, nrows ), true);
	string window_names[ NUM_THREADS ];
	
	for( int i = 0; i < NUM_THREADS; i++ )
	{
		cam[ i ].open( i + 1 );
		
		cam[ i ].set( CV_CAP_PROP_FRAME_WIDTH, ncols);
		cam[ i ].set( CV_CAP_PROP_FRAME_HEIGHT, nrows);

		stringstream ss;
		ss << i;
	
		window_names[ i ] = ss.str();
	
		namedWindow( window_names[ i ], CV_WINDOW_NORMAL | CV_WINDOW_KEEPRATIO );
	}

	namedWindow( "combined", CV_WINDOW_NORMAL | CV_WINDOW_KEEPRATIO );
	for( ;; )
	{
		Mat cap[ NUM_THREADS ];
		Mat grays[ NUM_THREADS ];
		Mat combined( nrows, ncols * 2, CV_8UC1 );
		Mat combined_color( nrows, ncols * 2, CV_32FC3); 
	
		#pragma omp parallel for
		for( int curr_vid = 0; curr_vid < NUM_THREADS; curr_vid++)
		{
			cam[ curr_vid ] >> cap[ curr_vid ];
			grays[ curr_vid ].create( nrows, ncols, CV_8UC1 );
			cvtColor( cap[ curr_vid ], grays[ curr_vid ], CV_BGR2GRAY );
		}
	
		for(int row = 0; row < nrows; row++ )
		{
			for( int col = 0; col < ncols; col++ )
			{
				combined.at<unsigned char>( row, col ) = grays[ 1  ].at<unsigned char>( row, col );
				combined.at<unsigned char>( row, col + ncols ) = grays[ 0 ].at<unsigned char>( row, col );
				//combined.at<unsigned char>( row, col + ncols ) = grays[ 2 ].at<unsigned char>( row, col );
				//combined.at<unsigned char>( row + nrows, col + ncols ) = grays[ 3 ].at<unsigned char>( row, col );
			}
		}
		
		for( int curr_vid = 0; curr_vid < NUM_THREADS; curr_vid++)
		{
			imshow( window_names[ curr_vid ], cap[ curr_vid ] );
		}
		

		cvtColor( combined, combined_color, CV_GRAY2BGR );
		imwrite("images/Gray_Img.jpg", combined );
		//imwrite("images/Color_Img.jpg", combined_color );
		imshow( "combined", combined);
	
		if(waitKey(5) >= 0) break;
	}
	
}

void combine_imgs( )
{
}

void set_exposure( int curr_exp )
{
   ostringstream convert;
   string curr_string;
   
   convert << curr_exp;

   curr_string = exposure_base + convert.str();

   system( curr_string.c_str() );
}




